package com.telehot.location;

import android.Manifest;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.res.ResourcesCompat;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.MyLocationConfiguration;
import com.baidu.mapapi.map.MyLocationConfiguration.LocationMode;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.map.Polyline;
import com.baidu.mapapi.map.PolylineOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.DistanceUtil;
import com.google.gson.reflect.TypeToken;
import com.longsh.optionframelibrary.OptionBottomDialog;
import com.telehot.location.bean.LocationBean;
import com.telehot.location.util.GsonUtils;
import com.telehot.location.util.OperateFile;
import com.ytlibrary.BaseFunction;
import com.ytlibrary.dialog.IDialog;
import com.ytlibrary.dialog.impl.DialogLibrary;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import me.weyye.hipermission.HiPermission;
import me.weyye.hipermission.PermissionCallback;
import me.weyye.hipermission.PermissonItem;

import static com.ytlibrary.BaseFunction.showToast;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private DialogLibrary dialogLibrary; //Dialog库组件
    private OperateFile mOperateFile;  //对读写文件的一些针对性操作

    private Button open_or_close;  //开启关闭按钮
    private boolean isOpen = false;  //是否开启关闭状态  true:开启状态    false:关闭状态

    boolean isFirstLoc = true; // 是否首次定位
    List<LatLng> points = new ArrayList<>();//位置点集合
    Polyline mPolyline;       //绘制线
    BitmapDescriptor startBD;  //开始图标
    BitmapDescriptor finishBD;  //结束图标
    private boolean isDynamic = true;  //是否动态绘制   true：动态绘制  false：绘制定位点

    // 定位相关
    private MapView mMapView;
    public MyLocationListenner myListener = new MyLocationListenner();
    private BaiduMap mBaiduMap;
    private LocationClient mLocClient;
    private Double lastX = 0.0;
    private double mCurrentLat = 0.0;
    private double mCurrentLon = 0.0;
    private int mCurrentDirection = 0;
    private float mCurrentAccracy;
    private MyLocationData locData;
    private SensorManager mSensorManager;
    MapStatus.Builder builder;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //初始化百度地图
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);

        initView();  //初始化布局
        initData();  //初始化数据
        initPermissions(); //申请权限
        initLocation();  //初始化定位
    }

    private void initView() {
        open_or_close = findViewById(R.id.open_or_close);
        mMapView = findViewById(R.id.tracing_mapView);  //获取地图控件引用
    }

    private void initData() {
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);// 获取传感器管理服务

        new BaseFunction(this);  //基础库
        dialogLibrary = new DialogLibrary(this);  //dialog控件对象
        mOperateFile = new OperateFile(this);
    }

    private void initLocation() {
        mBaiduMap = mMapView.getMap();
        //显示正常图层
        mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
        // 开启定位图层，一定不要少了这句，否则对在地图的设置、绘制定位点将无效
        mBaiduMap.setMyLocationEnabled(true);
        //对定位的图标进行配置，需要MyLocationConfiguration实例，这个类是用设置定位图标的显示方式的
        mBaiduMap.setMyLocationConfiguration(new MyLocationConfiguration(LocationMode.FOLLOWING, true, null));

        startBD = BitmapDescriptorFactory.fromResource(R.drawable.ic_me_history_startpoint);
        finishBD = BitmapDescriptorFactory.fromResource(R.drawable.ic_me_history_finishpoint);
    }


    /**
     * 点击开启关闭时的操作
     * isOpen仅表示目前定位情况   true:正在定位    false:停止定位
     * 该方法每调用一次,即说明状态需要改变一次
     * @param view
     */
    public void openOrClose(View view) {
        if (isOpen) {
            //此时处于正在开启状态,需要关闭定位
            open_or_close.setText("开启");
            mLocClient.stop();   //停止定位
            isDynamic = false;  //关闭动态绘制
            isOpen = false;  //此时正在关闭定位服务
            dealData(); //处理加保存数据
        } else {
            //此时处于正在关闭状态,需要开启定位
            open_or_close.setText("关闭");
            //开启定位之前,初始化下地图轨迹
            mMapView.getMap().clear();
            last = null;
            startLocation();   //开启定位
            isDynamic = true;  //开启动态绘制
            isOpen = true;   //此时正在开启定位服务
        }

    }


    /**
     * 开始定位
     */
    private void startLocation() {
        // 定位初始化
        mLocClient = new LocationClient(this);
        mLocClient.registerLocationListener(myListener);
        LocationClientOption option = new LocationClientOption();
        option.setOpenGps(true); // 打开gps
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//只用gps定位，需要在室外定位。
        option.setCoorType("bd09ll"); // 设置坐标类型
        option.setScanSpan(1000);  // 定位点时间间隔1000ms
        //可选，设置是否需要设备方向结果
        option.setNeedDeviceDirect(true);
        mLocClient.setLocOption(option);
        mLocClient.start();
    }

    /**
     * 定位SDK监听函数
     */
    public class MyLocationListenner implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation location) {
            // map view 销毁后不在处理新接收的位置
            if (location == null || mMapView == null) {
                return;
            }
            mCurrentLat = location.getLatitude();   //获取纬度信息
            mCurrentLon = location.getLongitude(); //获取经度信息
            mCurrentAccracy = location.getRadius();  //获取定位精度，默认值为0.0f

            //动态加载轨迹
            if (isDynamic) {
                try {
                    initDynamicTrack(location);
                } catch (Exception e) {
                    Log.i("轨迹绘制", "动态绘制报错" + e.toString());
                }
            }

            locData = new MyLocationData.Builder().accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息，顺时针0-360
                    .direction(mCurrentDirection).latitude(location.getLatitude()).longitude(location.getLongitude()).build();
            mBaiduMap.setMyLocationData(locData);
            if (isFirstLoc) {
                isFirstLoc = false;
                LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
                MapStatus.Builder builder = new MapStatus.Builder();
                builder.target(ll).zoom(18.0f);
                mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
            }
        }
    }

    /**
     * 设置功能
     * @param view
     */
    public void setting(View view) {
        dialogLibrary.bottomDialog("查看绘制轨迹", "实时绘制轨迹", new IDialog.OnBottomDialogClick() {
            @Override
            public void onTopButtonClick() {
                checkTrack();
                //如果处于开启状态,则选择去关闭
                if (isOpen) {
                    openOrClose(null);
                }
            }

            @Override
            public void onMidButonClick() {
                if (!isOpen) openOrClose(null);
            }
        });
    }

    /**
     * 查看轨迹
     */
    private void checkTrack() {
        //设置类型
        Type listType = new TypeToken<List<LocationBean>>(){}.getType();
        final List<LocationBean> locationBeanList = GsonUtils.jsonToList(mOperateFile.readFileContent(), listType);
        Log.i("yutao", mOperateFile.readFileContent());
        List<String> list = new ArrayList<>();

        if (locationBeanList == null) return;
        for (int i = 0; i < locationBeanList.size(); i++) {
            list.add(locationBeanList.get(i).getTime() + "  轨迹绘制");
        }

        final DialogLibrary dialogLibrary = new DialogLibrary(this);
        dialogLibrary.bottomListDialog(list, new IDialog.OnBottomListListener() {
            @Override
            public void onClick(final int position, boolean isLongClick) {
                if(!isLongClick){
                    initStaticTrack(locationBeanList.get(position).getLatLngList());
                    dialogLibrary.setBottomListDialog().dismiss();
                }

                if (isLongClick) {
                    String str = "是否移除 " + locationBeanList.get(position).getTime() + "轨迹记录";
                    dialogLibrary.commonDialog(str, new IDialog.OnCommonDialogClick() {
                        @Override
                        public void affirmOnClick() {
                            if (dialogLibrary.setBottomListDialog().removeData(position) == 0) {
                                dialogLibrary.setBottomListDialog().dismiss();
                            }
                            locationBeanList.remove(position);
                            mOperateFile.coverFileContent(GsonUtils.toJson(locationBeanList));
                        }
                    });

                }


            }
        });
    }


    /**
     * 处理数据
     */
    private void dealData() {
        //获取当前时间
        Date date = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = df.format(date);

        List<LocationBean> locationBeanList = new ArrayList<>();
        locationBeanList.add(new LocationBean());
        locationBeanList.get(0).setTime(time);  //存入时间
        locationBeanList.get(0).setLatLngList(points);   //存入轨迹点

        if (points.size() < 2) {
            showToast("轨迹点少于俩个，无法保存");
            return;
        }

        mOperateFile.saveFileContent(GsonUtils.toJson(locationBeanList));  //保存该点轨迹
    }


    /**
     * 动态绘制轨迹
     */
    LatLng last = new LatLng(0, 0);//上一个定位点
    float mCurrentZoom = 18f;//默认地图缩放比例值
    boolean isFirstDynamicLoc = true;
    private void initDynamicTrack(BDLocation location) {
        if (isFirstDynamicLoc) {//首次定位
            //第一个点很重要，决定了轨迹的效果，gps刚开始返回的一些点精度不高，尽量选一个精度相对较高的起始点
            LatLng ll = getMostAccuracyLocation(location);

            if(ll == null){
                return;
            }
            isFirstDynamicLoc = false;
            points.add(ll);//加入集合
            last = ll;

            //显示当前定位点，缩放地图
            locateAndZoom(location, ll);

            //标记起点图层位置
            MarkerOptions oStart = new MarkerOptions();// 地图标记覆盖物参数配置类
            oStart.position(points.get(0));// 覆盖物位置点，第一个点为起点
            oStart.icon(startBD);// 设置覆盖物图片
            mBaiduMap.addOverlay(oStart); // 在地图上添加此图层

            return;//画轨迹最少得2个点，首地定位到这里就可以返回了
        }

        //从第二个点开始
        LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
        //sdk回调gps位置的频率是1秒1个，位置点太近动态画在图上不是很明显，可以设置点之间距离大于为5米才添加到集合中
        if (DistanceUtil.getDistance(last, ll) < 5) {
            return;
        }

        points.add(ll);//如果要运动完成后画整个轨迹，位置点都在这个集合中
        Log.i("轨迹绘制", "经度:" + location.getLatitude() + "  纬度:" + location.getLongitude());


        last = ll;

        //显示当前定位点，缩放地图
        locateAndZoom(location, ll);

        //清除上一次轨迹，避免重叠绘画
        mMapView.getMap().clear();

        //起始点图层也会被清除，重新绘画
        MarkerOptions oStart = new MarkerOptions();
        oStart.position(points.get(0));
        oStart.icon(startBD);
        mBaiduMap.addOverlay(oStart);

        //将points集合中的点绘制轨迹线条图层，显示在地图上
        OverlayOptions ooPolyline = new PolylineOptions().width(13).color(0xAAFF0000).points(points);
        mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
    }

    /**
     * 绘制静态点轨迹
     */
    private void initStaticTrack(List<LatLng> latLngs) {
        if (latLngs.size() < 2) {
            showToast("该条轨迹记录,定位点少于俩个,无法绘制");
            return;
        }

        //定位到起点位置
        builder = new MapStatus.Builder();
        builder.target(latLngs.get(0)).zoom(mCurrentZoom);
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));

        MarkerOptions oStart = new MarkerOptions();//地图标记覆盖物参数配置类
        oStart.position(latLngs.get(0));//覆盖物位置点，第一个点为起点
        oStart.icon(startBD);//设置覆盖物图片
        oStart.zIndex(1);//设置覆盖物Index
        mBaiduMap.addOverlay(oStart); //在地图上添加此图层

        //添加终点图层
        MarkerOptions oFinish = new MarkerOptions().position(latLngs.get(latLngs.size()-1)).icon(finishBD).zIndex(2);
        mBaiduMap.addOverlay(oFinish);


        /**
         * 配置线段图层参数类： PolylineOptions
         * ooPolyline.width(13)：线宽
         * ooPolyline.color(0xAAFF0000)：线条颜色红色
         * ooPolyline.points(latLngs)：List<LatLng> latLngs位置点，将相邻点与点连成线就成了轨迹了
         */
        OverlayOptions ooPolyline = new PolylineOptions().width(8).color(0xAAFF0000).points(latLngs);

        //在地图上画出线条图层，mPolyline：线条图层
        mPolyline = (Polyline) mBaiduMap.addOverlay(ooPolyline);
        mPolyline.setZIndex(3);
    }


    /**
     * 首次定位很重要，选一个精度相对较高的起始点
     * 注意：如果一直显示gps信号弱，说明过滤的标准过高了，
     你可以将location.getRadius()>25中的过滤半径调大，比如>40，
     并且将连续5个点之间的距离DistanceUtil.getDistance(last, ll ) > 5也调大一点，比如>10，
     这里不是固定死的，你可以根据你的需求调整，如果你的轨迹刚开始效果不是很好，你可以将半径调小，两点之间距离也调小，
     gps的精度半径一般是10-50米
     */
    private LatLng getMostAccuracyLocation(BDLocation location){

        if (location.getRadius()>40) {//gps位置精度大于40米的点直接弃用
            return null;
        }

        LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());

        if (DistanceUtil.getDistance(last, ll ) > 10) {
            last = ll;
            points.clear();//有任意连续两点位置大于10，重新取点
            return null;
        }
        points.add(ll);
        last = ll;
        //有5个连续的点之间的距离小于10，认为gps已稳定，以最新的点为起始点
        if(points.size() >= 5){
            points.clear();
            return ll;
        }
        return null;
    }

    /**
     * 缩放并定位到当前位置
     * @param location
     * @param ll
     */
    private void locateAndZoom(final BDLocation location, LatLng ll) {
        mCurrentLat = location.getLatitude();
        mCurrentLon = location.getLongitude();
        locData = new MyLocationData.Builder().accuracy(0)
                // 此处设置开发者获取到的方向信息，顺时针0-360
                .direction(mCurrentDirection).latitude(location.getLatitude())
                .longitude(location.getLongitude()).build();
        mBaiduMap.setMyLocationData(locData);

        builder = new MapStatus.Builder();
        builder.target(ll).zoom(mCurrentZoom);
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
    }


    //初始化一系列权限
    private void initPermissions(){
        List<PermissonItem> permissonItems = new ArrayList<PermissonItem>();
        permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "读写权限", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.ACCESS_FINE_LOCATION, "定位信息", R.drawable.permission_ic_location));
        HiPermission.create(this)
                .title("开启权限")
                .permissions(permissonItems)
                .filterColor(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, getTheme()))//图标的颜色
                .msg("为了能正常使用该软件,请开启以下权限。")
                .style(R.style.PermissionBlueStyle)
                .checkMutiPermission(new PermissionCallback() {
                    @Override
                    public void onClose() {

                    }

                    @Override
                    //权限申请完成后操作
                    public void onFinish() {
                        initLocation();  //初始化位置
                    }

                    @Override
                    public void onDeny(String permisson, int position) {
                        Log.i("yutao", "onDeny");
                    }

                    @Override
                    public void onGuarantee(String permisson, int position) {
                        Log.i("yutao", "onGuarantee");
                    }
                });
    }

    @Override
    protected void onResume() {
        //在activity执行onResume时必须调用mMapView. onResume ()
        mMapView.onResume();

        super.onResume();
        // 为系统的方向传感器注册监听器
        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_UI);
    }
    @Override
    protected void onPause() {
        super.onPause();
        //在activity执行onPause时必须调用mMapView. onPause ()
        mMapView.onPause();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在activity执行onDestroy时必须调用mMapView.onDestroy()
        mMapView.onDestroy();
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        //每次方向改变，重新给地图设置定位数据，用上一次onReceiveLocation得到的经纬度、精度
        double x = sensorEvent.values[SensorManager.DATA_X];
        if (Math.abs(x - lastX) > 1.0) {// 方向改变大于1度才设置，以免地图上的箭头转动过于频繁
            mCurrentDirection = (int) x;
            locData = new MyLocationData.Builder().accuracy(mCurrentAccracy)
                    // 此处设置开发者获取到的方向信息，顺时针0-360
                    .direction(mCurrentDirection).latitude(mCurrentLat).longitude(mCurrentLon).build();

            try {
                mBaiduMap.setMyLocationData(locData);
            } catch (Exception e) {
                Log.i("轨迹绘制", e.toString());
            }
        }
        lastX = x;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }


}
